package com.bestow.dox4j.component.handler;

import com.bestow.basic.domain.HlsDocFileParaTable;
import com.bestow.dox4j.Docx4jConstants;
import com.bestow.dox4j.IBookmarkHandler;
import com.bestow.dox4j.utils.Docx4jUtils;
import org.docx4j.XmlUtils;
import org.docx4j.jaxb.Context;
import org.docx4j.jaxb.XPathBinderAssociationIsPartialException;
import org.docx4j.model.structure.SectionWrapper;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.Part;
import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage;
import org.docx4j.openpackaging.parts.WordprocessingML.HeaderPart;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.relationships.Relationship;
import org.docx4j.wml.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import java.io.File;
import java.util.*;

/**
 * Created by fjm on 2017/12/11.
 */
@Component
public class WatermarkBookmarkHandler implements IBookmarkHandler {
    protected static Logger log = LoggerFactory.getLogger(WatermarkBookmarkHandler.class);
    private static ObjectFactory factory = Context.getWmlObjectFactory();
    private boolean deleteComment = true;
    private boolean spDeal = false;


    @Override
    public String getType() {
        return Docx4jConstants.BOOKMARK_TYPE_WATERMARK;
    }

    @Override
    public void process(WordprocessingMLPackage wordMLPackage, List<HlsDocFileParaTable> tableColumnList, List<HashMap> bookMarkValueList, String bookmark, Map<String, Object> params) throws Exception {
        replaceBookmarkFromContent(wordMLPackage, params);
    }


    public void replaceBookmarkFromContent(WordprocessingMLPackage wordMLPackage, Map result) throws Exception {
        Object imgPathObj = result.get("imgPath" );
        String imgPath = null;
        if (imgPathObj != null) {
            imgPath = imgPathObj.toString();
        }
        if (spDeal) {
            if (imgPath == null) {
                log.debug("img path could be empty" );
                return;
            }
            File img = new File(imgPath);
            if (!img.exists()) {
                log.debug("img path not exists" );
            }
            // 添加水印
            addWatermarkAndDeleteComments(wordMLPackage, "TMP_IMG" , imgPath, null, null, null);
        } else {
            if (!result.isEmpty()) {
                Object bookmark = result.get("bookmark" );
                if (bookmark == null) {
                    return;
                }
                String bookmarkValue = bookmark.toString();
                //if (bookmarkTypeWatermark.endsWith(bookmarkValue)) {
                if (true) {
                    addWatermarkAndDeleteComments(wordMLPackage, result);
                }
            }

        }
    }

    public void addWatermarkAndDeleteComments(WordprocessingMLPackage wordMLPackage, Map result) throws Exception {
        if (!result.isEmpty()) {
            Map compositeMap = result;
            String filePath = compositeMap.get("imgPath" ) != null ? compositeMap.get("imgPath" ).toString() : "";
            String name = compositeMap.get("bookmark" ) != null ? compositeMap.get("bookmark" ).toString() : "";
            String content = compositeMap.get("bookmarkValue" ) != null ? compositeMap.get("bookmarkValue" ).toString() : "";
            String fontFamily = compositeMap.get("fontFamily" ) != null ? compositeMap.get("fontFamily" ).toString() : "";
            String fontSize = compositeMap.get("fontSize" ) != null ? compositeMap.get("fontSize" ).toString() : "";
            String bookmarkType = compositeMap.get("bookmarkType" ) != null ? compositeMap.get("bookmarkType" ).toString() : "";
            if ("WATERMARK".equals(bookmarkType)) {
                addWatermarkAndDeleteComments(wordMLPackage, name, content, fontFamily, fontSize, filePath);
            }
        }
        log.info("Done" );
    }


    public void addWatermarkAndDeleteComments(WordprocessingMLPackage wordMLPackage, String name, String content,
                                              String font, String fontSize, String filePath) throws Exception {
        MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart(); // 获取文件主体部分
        Part header1 = Docx4jUtils.getNamedPart(wordMLPackage, "/word/header1.xml" );
        if (header1 == null) {
            header1 = Docx4jUtils.getNamedPart(wordMLPackage, "/word/header.xml" );
        }
        if (header1 == null) {
            // header1 不存在则需要创建
            header1 = new HeaderPart();
            header1.setPackage(wordMLPackage);
            Relationship relationship = documentPart.addTargetPart(header1);
            createHeaderReference(wordMLPackage, relationship);
        }
        // 先删除批注
        if (deleteComment) {
            deleteAllComments(wordMLPackage);
            log.info("批注删除完成" );
        }
        // 再添加水印,_IMG结尾的为图片水印,content中保存图片的路径
        if (name != null && name.endsWith("_IMG" )) {
            addImageWatermark(wordMLPackage, header1, filePath);
        } else {
            addTextWatermark(header1, content, font, fontSize);
        }
        log.info("水印添加完成" );

    }

    private static void addTextWatermark(Part header, String content, String font, String fontSize)
            throws JAXBException {
        List<Object> headContent = Docx4jUtils.getPartContent(header);
        if (headContent == null) {
            headContent = new ArrayList<Object>(3);
        }
        P p = null;
        if (headContent.isEmpty()) {
            // 为空说明header为新创建的，需要添加p标签
            p = createP();
            headContent.add(p);
        } else {
            for (Object object : headContent) {
                if (object instanceof P) {
                    p = (P) object;
                }
            }
            if (p == null) {
                p = createP();
                headContent.add(p);
            }
        }
        R r = factory.createR();
        p.getContent().add(r);

        String template = "<w:pict " + "xmlns:v=\"urn:schemas-microsoft-com:vml\" "
                + "xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" "
                + "xmlns:o=\"urn:schemas-microsoft-com:office:office\" "
                + "xmlns:w10=\"urn:schemas-microsoft-com:office:word\">"
                + "<v:shape id=\"PowerPlusWaterMarkObject445461\" o:spid=\"_x0000_s2050\" type=\"#_x0000_t136\" "
                + "style=\"position:absolute;left:0;text-align:left;"
                + "margin-left:0;margin-top:0;width:238.5pt;height:39.75pt;"
                + "rotation:315;z-index:-251655168;mso-position-horizontal:center;"
                + "mso-position-horizontal-relative:margin;mso-position-vertical:center;"
                + "mso-position-vertical-relative:margin\" o:allowincell=\"f\" "
                + "fillcolor=\"silver\" stroked=\"f\">"
                + "<v:textpath style=\"font-family:'宋体';font-size:{fontSize}pt\" string=\"{content}\"/>"
                + "<w10:wrap anchorx=\"margin\" anchory=\"margin\"/>" + "</v:shape>" + "</w:pict>";
        template = template.replace("{content}" , content);
        if (font != null) {
            template = template.replace("宋体" , font);
        }
        if (fontSize == null) {
            fontSize = "40";
        }
        template = template.replace("{fontSize}" , fontSize);
        Object pictJAXB = XmlUtils.unmarshalString(template);

        r.getContent().add(pictJAXB);
    }


    public static void addImageWatermark(WordprocessingMLPackage wordMLPackage, Part header, String imgPath)
            throws Exception {
        log.debug("img path: {}" , imgPath);
        BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wordMLPackage, header, new File(
                imgPath));
        Relationship relationship = imagePart.addTargetPart(header);
        List<Relationship> rels = imagePart.getRels();
        String relId = relationship.getId();
        if (rels != null && !rels.isEmpty()) {
            relId = rels.get(0).getId();
        }
        log.debug("rel id: {}" , relId);
        P p = null;
        List<Object> partContent = Docx4jUtils.getPartContent(header);
        if (partContent.isEmpty()) {
            // 为空说明header为新创建的，需要添加p标签
            p = createP();
            partContent.add(p);
        } else {
            for (Object object : partContent) {
                if (object instanceof P) {
                    p = (P) object;
                }
            }
            if (p == null) {
                p = createP();
                partContent.add(p);
            }
        }
        R r = factory.createR();
        p.getContent().add(r);
        String template = "<w:pict "
                + "xmlns:v=\"urn:schemas-microsoft-com:vml\" "
                + "xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" "
                + "xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" "
                + "xmlns:o=\"urn:schemas-microsoft-com:office:office\" "
                + "xmlns:w10=\"urn:schemas-microsoft-com:office:word\"> "
                + "<v:shapetype id=\"_x0000_t75\" coordsize=\"21600,21600\" "
                + "o:spt=\"75\" o:preferrelative=\"t\" path=\"m@4@5l@4@11@9@11@9@5xe\" "
                + "filled=\"f\" stroked=\"f\"><v:stroke joinstyle=\"miter\"/>"
                + "<v:formulas>"
                + "<v:f eqn=\"if lineDrawn pixelLineWidth 0\"/>"
                + "<v:f eqn=\"sum @0 1 0\"/>"
                + "<v:f eqn=\"sum 0 0 @1\"/>"
                + "<v:f eqn=\"prod @2 1 2\"/>"
                + "<v:f eqn=\"prod @3 21600 pixelWidth\"/>"
                + "<v:f eqn=\"prod @3 21600 pixelHeight\"/>"
                + "<v:f eqn=\"sum @0 0 1\"/>"
                + "<v:f eqn=\"prod @6 1 2\"/>"
                + "<v:f eqn=\"prod @7 21600 pixelWidth\"/>"
                + "<v:f eqn=\"sum @8 21600 0\"/>"
                + "<v:f eqn=\"prod @7 21600 pixelHeight\"/>"
                + "<v:f eqn=\"sum @10 21600 0\"/>"
                + "</v:formulas>"
                + "<v:path o:extrusionok=\"f\" gradientshapeok=\"t\" o:connecttype=\"rect\"/>"
                + "<o:lock v:ext=\"edit\" aspectratio=\"t\"/>"
                + "</v:shapetype>"
                + "<v:shape id=\"WordPictureWatermark9049853\" o:spid=\"_x0000_s2050\" "
                + "type=\"#_x0000_t75\" "
                + "style=\"position:absolute;left:0;text-align:left;margin-left:0;margin-top:0;width:415.2pt;height:464.85pt;z-index:-251657216;mso-position-horizontal:center;mso-position-horizontal-relative:margin;mso-position-vertical:center;mso-position-vertical-relative:margin\" o:allowincell=\"f\">"
                + "<v:imagedata r:id=\"{relId}\" o:title=\"watermark\"/>" + "</v:shape>" + "</w:pict>";
        template = template.replace("{relId}" , relId);
        Object pictJAXB = XmlUtils.unmarshalString(template);
        r.getContent().add(pictJAXB);
    }

    private static P createP() {
        P p = factory.createP();
        PPr pPr = factory.createPPr();
        p.getContent().add(pPr);
        return p;
    }

    private static void deleteAllComments(WordprocessingMLPackage wordMLPackage)
            throws XPathBinderAssociationIsPartialException, JAXBException {
        if (wordMLPackage == null) {
            return;
        }
        MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart();

        // 通过xpath找到所有的批注开始标签
        deleteAllCommentRangeStart(documentPart);

        // 通过xpath找到所有的批注结束标签
        deleteAllCommentRangeEnd(documentPart);

        // 通过xpath找到所有的批注引用标签
        deleteAllCommentReference(documentPart);

    }

    private static void deleteAllCommentRangeEnd(MainDocumentPart documentPart) throws JAXBException,
            XPathBinderAssociationIsPartialException {
        String xpath = "//w:commentRangeEnd";
        List<Object> endNodesList = documentPart.getJAXBNodesViaXPath(xpath, false);
        if (endNodesList != null && !endNodesList.isEmpty()) {
            for (int i = 0; i < endNodesList.size(); i++) {
                Object object = endNodesList.get(i);
                if (object instanceof CommentRangeEnd) {
                    CommentRangeEnd start = (CommentRangeEnd) object;
                    Object parent = start.getParent();
                    if (parent instanceof ContentAccessor) {
                        ContentAccessor accessor = (ContentAccessor) parent;
                        accessor.getContent().remove(start);
                    }
                }
            }
        }
    }

    private static void deleteAllCommentRangeStart(MainDocumentPart documentPart) throws JAXBException,
            XPathBinderAssociationIsPartialException {
        String xpath = "//w:commentRangeStart";
        List<Object> startNodesList = documentPart.getJAXBNodesViaXPath(xpath, false);

        if (startNodesList != null && !startNodesList.isEmpty()) {
            for (int i = 0; i < startNodesList.size(); i++) {
                Object object = startNodesList.get(i);
                if (object instanceof CommentRangeStart) {
                    CommentRangeStart start = (CommentRangeStart) object;
                    Object parent = start.getParent();
                    if (parent instanceof ContentAccessor) {
                        ContentAccessor accessor = (ContentAccessor) parent;
                        accessor.getContent().remove(start);
                    }
                }
            }
        }
    }

    private static void deleteAllCommentReference(MainDocumentPart documentPart) throws JAXBException,
            XPathBinderAssociationIsPartialException {
        String xpath = "//w:commentReference/..";
        List<Object> referNodesList = documentPart.getJAXBNodesViaXPath(xpath, false);
        // 遍历找到的父标签
        if (referNodesList != null && !referNodesList.isEmpty()) {
            for (int i = 0; i < referNodesList.size(); i++) {
                Object object = XmlUtils.unwrap(referNodesList.get(i));
                if (object instanceof ContentAccessor) {
                    ContentAccessor accessor = (ContentAccessor) object;
                    List<Object> content = accessor.getContent();
                    Iterator<Object> iterator = content.iterator();
                    while (iterator.hasNext()) {
                        Object o = iterator.next();
                        if (o instanceof R.CommentReference) {
                            iterator.remove();
                        } else if (o instanceof JAXBElement) {
                            JAXBElement element = (JAXBElement) o;
                            if (XmlUtils.unwrap(element) instanceof R.CommentReference) {
                                iterator.remove();
                            }
                        }
                    }
                }
            }
        }
    }

    private static void createHeaderReference(WordprocessingMLPackage wordMLPackage, Relationship relationship) {
        List<SectionWrapper> sections = wordMLPackage.getDocumentModel().getSections();
        SectPr sectPr = sections.get(sections.size() - 1).getSectPr();
        if (sectPr == null) {
            sectPr = factory.createSectPr();
            wordMLPackage.getMainDocumentPart().addObject(sectPr);
            sections.get(sections.size() - 1).setSectPr(sectPr);
        }
        HeaderReference headerReference = factory.createHeaderReference();
        headerReference.setId(relationship.getId());
        headerReference.setType(HdrFtrRef.DEFAULT);
        sectPr.getEGHdrFtrReferences().add(headerReference);
    }

}
